package cn.daomeng.firebird.core.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;

import cn.daomeng.firebird.core.environment.CalorieEnvironment;
import cn.daomeng.firebird.core.utils.StringUtils;
import cn.hutool.json.JSONUtil;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;


/**
 * @author wf.shu
 * @version 1.0.0.0
 * @since
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

	@Value("${spring.application.name:firebird}")
	private String appName;
	@Value("${spring.application.appDesc: this is firebird.}")
	private String appDesc;
	@Value("${swagger.show:false}")
	private boolean swaggerShow;
	@Value("${swagger.scan.packages:cn.daomeng.firebird}")
	private String swaggerScan;

    @Value("${swagger.gloabl.header:}")
    private String swaggerGloablHeader;




	@Autowired
	private CalorieEnvironment calorieEnvironment;
	@Bean
	public Docket createRestApi() {
	    //如果是生产环境，则强制关闭Swagger
	    if(calorieEnvironment.isProduct()){
	        swaggerShow = false;
        }

        List<Parameter> pars = new ArrayList<Parameter>();
	    if(StringUtils.isNotBlank(swaggerGloablHeader)){
            List<SwaggerGloablHeader> headerList = JSONUtil.toList(JSONUtil.parseArray(swaggerGloablHeader), SwaggerGloablHeader.class);
            for(SwaggerGloablHeader header : headerList){
                String name = header.getName();
                String desc = header.getDesc();
                Boolean required = header.getRequired();
                ParameterBuilder tokenPar = new ParameterBuilder();
                tokenPar.name(name).description(desc).modelRef(new ModelRef("string")).parameterType("header").required(required).build();
                pars.add(tokenPar.build());

            }
        }
		return new Docket(DocumentationType.SWAGGER_2).enable(swaggerShow).apiInfo(apiInfo()).select()
				.apis(basePackage(swaggerScan)).paths(PathSelectors.any()).build()
                .globalOperationParameters(pars);
	}

    /**
     * Predicate that matches RequestHandler with given base package name for the class of the handler method.
     * This predicate includes all request handlers matching the provided basePackage
     *
     * @param basePackage - base package of the classes
     * @return this
     */
    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                return declaringClass(input).transform(handlerPackage(basePackage)).or(true);
            }
        };
    }

    /**
     * 处理包路径配置规则,支持多路径扫描匹配以逗号隔开
     *
     * @param basePackage 扫描包路径
     * @return Function
     */
    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
        return new Function<Class<?>, Boolean>() {
            @Override
            public Boolean apply(Class<?> input) {
                for (String strPackage : basePackage.split(",")) {
                    boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                    if (isMatch) {
                        return true;
                    }
                }
                return false;
            }
        };
    }

    /**
     * @param input RequestHandler
     * @return Optional
     */
    private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
        return Optional.fromNullable(input.declaringClass());
    }

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder().title(appName).description(appDesc).termsOfServiceUrl("http://www.geely.com")
				// .version("11.0")
				.build();
	}
}
